package rtpencoder

import (
	"bytes"
	"crypto/rand"
	"fmt"

	"github.com/pion/rtp"
)

type _rtpEncoder struct {
	// payload type of packets.
	PayloadType uint8

	// SSRC of packets (optional).
	// It defaults to a random value.
	SSRC *uint32

	// initial sequence number of packets (optional).
	// It defaults to a random value.
	InitialSequenceNumber *uint16

	// maximum size of packet payloads (optional).
	// It defaults to 1460.
	PayloadMaxSize int

	sequenceNumber uint16

	packets rtp.Packetizer
}

// Init initializes the encoder.
func (e *_rtpEncoder) Init() error {
	const defaultPayloadMaxSize = 1460 // 1500 (UDP MTU) - 20 (IP header) - 8 (UDP header) - 12 (RTP header)

	var randUint32 = func() (uint32, error) {
		var b [4]byte
		_, err := rand.Read(b[:])
		if err != nil {
			return 0, err
		}
		return uint32(b[0])<<24 | uint32(b[1])<<16 | uint32(b[2])<<8 | uint32(b[3]), nil
	}

	if e.SSRC == nil {
		v, err := randUint32()
		if err != nil {
			return err
		}
		e.SSRC = &v
	}
	if e.InitialSequenceNumber == nil {
		v, err := randUint32()
		if err != nil {
			return err
		}
		v2 := uint16(v)
		e.InitialSequenceNumber = &v2
	}
	if e.PayloadMaxSize == 0 {
		e.PayloadMaxSize = defaultPayloadMaxSize
	}

	e.sequenceNumber = *e.InitialSequenceNumber

	e.packets = rtp.NewPacketizer(uint16(e.PayloadMaxSize), e.PayloadType, *e.SSRC,
		new(rtpPayLoader),
		rtp.NewFixedSequencer(e.sequenceNumber),
		0,
	)

	return nil
}

// Encode encodes an audio frame into a RTP packet.
func (e *_rtpEncoder) Encode(frame []byte) ([]*rtp.Packet, error) {
	packets := e.packets.Packetize(frame, 0)
	return packets, nil
}

type rtpPayLoader struct{}

func (p *rtpPayLoader) Payload(mtu uint16, payload []byte) [][]byte {
	var out [][]byte
	if payload == nil || mtu <= 0 {
		return out
	}

	for len(payload) > int(mtu) {
		o := make([]byte, mtu)
		copy(o, payload[:mtu])
		payload = payload[mtu:]
		out = append(out, o)
	}

	if len(payload) > 0 {
		o := make([]byte, len(payload))
		copy(o, payload)
		return append(out, o)
	} else {
		return out
	}
}

type _rtpDecoder struct {
	packets []*rtp.Packet
}

func (d *_rtpDecoder) Init() error {
	return nil
}

func (d *_rtpDecoder) Decode(packet *rtp.Packet) ([]byte, error) {
	d.packets = append(d.packets, packet)

	if packet.Marker {
		packets := d.packets

		d.packets = []*rtp.Packet{}

		for i := 0; i < len(packets)-1; i++ {
			if packets[i].Timestamp != packets[i+1].Timestamp {
				return nil, fmt.Errorf("error timestamp")
			}
			if packets[i].SequenceNumber+1 != packets[i+1].SequenceNumber {
				return nil, fmt.Errorf("loss SequenceNumber")
			}
		}

		var buffer bytes.Buffer
		for _, pkt := range packets {
			buffer.Write(pkt.Payload)
		}

		return buffer.Bytes(), nil
	}

	return nil, fmt.Errorf("need more packets")
}
